﻿#ifndef _EASY_IOCP_CLIENT_H_
#define _EASY_IOCP_CLIENT_H_

#ifdef _WIN32

#include "EasyTcpClient.hpp"
#include "CELLClient.hpp"
#include "CELLIOCP.hpp"

class EasyIOCPClient : public EasyTcpClient
{
public:
	virtual ~EasyIOCPClient()
	{
		EasyTcpClient::Close();
	}

	// 发送数据
	// 处理网络消息
	virtual bool OnRun(int microseconds = 1) override
	{
		if (IsRun())
		{
			if (_pClient->needWrite())
			{
				auto pIoData = _pClient->makeSendIOData();
				if (pIoData)
				{
					if (!_iocp.postSend(pIoData))
					{
						Close();
						return false;
					}
				}
				//--
				pIoData = _pClient->makeRecvIOData();
				if (pIoData)
				{
					if (!_iocp.postRecv(pIoData))
					{
						Close();
						return false;
					}
				}
			}
			else {
				auto pIoData = _pClient->makeRecvIOData();
				if (pIoData)
				{
					if (!_iocp.postRecv(pIoData))
					{
						Close();
						return false;
					}
				}
			}

			// 循环处理事件直到没有事件发生为止
			while (true)
			{
				int ret = DoNetIOCPEvents(microseconds);
				if (ret < 0)
				{
					// IOCP出错
					return false;
				}
				else if (ret == 0)
				{
					// 没有事件发生
					// 处理数据
					DoMsg();
					return true;
				}
			}
			DoMsg();
			return true;
		}
		return false;
	}

	virtual void Close() override
	{
		_iocp.destory();
		EasyTcpClient::Close();
	}
protected:
	virtual void OnInitSocket() override
	{
		_iocp.create();
		_iocp.reg(_pClient->sockfd(), _pClient);
	}

	virtual void OnConnect() override;

	int DoNetIOCPEvents(int timeout)
	{
		int ret = _iocp.wait(_ioEvent, timeout);
		if (ret < 0)
		{
			// IOCP出错
			CELLLog_Error("EasyIOCPClient::DoNetEvents wait clientID<%d> socket<%d>", _pClient->id, (int)_pClient->sockfd());
			return ret;
		}
		else if (ret == 0)
		{
			// 没有事件发生
			return ret;
		}

		// 接收数据
		if (IO_TYPE::RECV == _ioEvent.pIOData->iotype)
		{// 接收数据完成
			if (_ioEvent.bytesTrans <= 0)
			{// 客户端断开
				CELLLog_Error("EasyIOCPClient::DoNetIOCPEvents rmclient sockfd=%d", (int)_ioEvent.pIOData->sockfd);
				Close();
				return ret;
			}
			// 告诉接收数据的客户端本次接收到了多少数据，用于接收缓冲区的数据位置的偏移
			CELLClient* pClient = (CELLClient*)_ioEvent.data.ptr;
			if (pClient)
				pClient->recv4Iocp(_ioEvent.bytesTrans);
			// CELLLog_Info("recv data: sockfd=%d, bytesTrans=%d", (int)_ioEvent.pIOData->sockfd, _ioEvent.bytesTrans);
		}
		else if (IO_TYPE::SEND == _ioEvent.pIOData->iotype)
		{// 发送数据完成
			if (_ioEvent.bytesTrans <= 0)
			{// 客户端断开
				CELLLog_Error("EasyIOCPClient::DoNetIOCPEvents rmclient sockfd=%d", (int)_ioEvent.pIOData->sockfd);
				Close();
				return ret;
			}
			// 通知发送缓冲区发送了多少数据
			CELLClient* pClient = (CELLClient*)_ioEvent.data.ptr;
			if (pClient)
				pClient->send2Iocp(_ioEvent.bytesTrans);
			// CELLLog_Info("send data: sockfd=%d, bytesTrans=%d", (int)_ioEvent.pIOData->sockfd, _ioEvent.bytesTrans);
		}
		else
		{
			//
			CELLLog_Error("undefined iotype");
		}
		return ret;
	}
private:
	CELLIOCP _iocp;

	IO_EVENT _ioEvent;
};

#endif // #ifdef _WIN32

#endif // #ifndef _EASY_IOCP_CLIENT_H_
